package com.qianxun.framework.common.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * md5工具
 * @author: huwei
 * @date:   2019/10/22 18:43
 * @version:  1.0.0
*/
public class Md5Util {
    /**
     * 盐值长度
     */
    private final Integer SALT_LENGTH = 12;
    /**
     * 加密方式
     */
    private final String ALGORITHM = "MD5";
    /**
     * 单例
     */
    private Md5Util(){}
    public static Md5Util getInstance(){
        return Md5UtilHolder.instance;
    }
    /**
     * 加密
     * @param str 待加密字符串
     * @return
     */
    public String encrypt(String str){
        return encrypt(str.getBytes());
    }
    /**
     * 加密
     * @param bytes 加密源数据字节数组
     * @return
     */
    public String encrypt(byte[] bytes){
        MessageDigest md = getMessageDigest();
        md.update(bytes);
        return Base64.getEncoder().encodeToString(md.digest());
    }
    /**
     * 校验字符串与加密字符串之前的数据是否相等
     * @param newStr 校验字符串
     * @param encryptStr 加密字符串
     * @return 相等返回 true ，反之false
     */
    public boolean valid(String newStr ,String encryptStr){
        return encryptStr.equals(encrypt(newStr));
    }
    /**
     * 盐值加密，即在待加密字符串中添加随机字符并加密
     * @param str 待加密字符串
     * @return
     */
    public String saltEncrypt(String str) {
        return saltEncrypt(str.getBytes());
    }
    /**
     * 校验字符串与加密字符串之前的数据是否相等
     * @param newStr 校验字符串
     * @param encryptStr 加密字符串
     * @return 相等返回 true ，反之false
     */
     public boolean saltValid(String newStr ,String encryptStr) {
        //base64解密编译过的字符
        byte[] encrypt = Base64.getDecoder().decode(encryptStr);
        //获取盐值
        byte[] salt = new byte[SALT_LENGTH];
        System.arraycopy(encrypt, 0, salt, 0, SALT_LENGTH);
        return encryptStr.equals(saltEncrypt(salt ,newStr.getBytes()));
    }
    /**
     * 获取md5的加密工具
     * @return
     */
    private MessageDigest getMessageDigest() {
        try {
            return MessageDigest.getInstance(ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 盐值加密
     * @param bytes 加密源数据字节数组
     * @return
     */
    private String saltEncrypt(byte[] bytes){
        //创建随机盐值
        SecureRandom secureRandom = new SecureRandom();
        byte[] saltBytes = new byte[SALT_LENGTH];
        secureRandom.nextBytes(saltBytes);
        return saltEncrypt(saltBytes ,bytes);
    }
    /**
     * 盐值加密
     * @param saltBytes 盐值字节数组
     * @param dataBytes 加密源数据字节数组
     * @return
     */
    private String saltEncrypt(byte[] saltBytes ,byte[] dataBytes){
        byte[] srcBytes = new byte[saltBytes.length + dataBytes.length];
        System.arraycopy(saltBytes ,0 ,srcBytes ,0 ,saltBytes.length);
        System.arraycopy(dataBytes ,0 ,srcBytes ,saltBytes.length ,dataBytes.length);
        //加密
        MessageDigest md = getMessageDigest();
        md.update(srcBytes);
        byte[] encryptBytes = md.digest();
        //封装盐值
        byte[] res = new byte[encryptBytes.length + saltBytes.length];
        System.arraycopy(saltBytes ,0 ,res ,0 ,saltBytes.length);
        System.arraycopy(encryptBytes ,0 ,res ,saltBytes.length ,encryptBytes.length);
        return Base64.getEncoder().encodeToString(res);
    }

    private static class Md5UtilHolder {
        static final Md5Util instance = new Md5Util();
    }
}
